package com.sp.business.normalization.impl.mf2;

import java.util.ArrayList;
import java.util.Collection;
import java.util.List;

import com.sp.business.objectmodel.NormalizedData;
import com.sp.generated.xml.firemon.Action;
import com.sp.generated.xml.firemon.ActionTypes;
import com.sp.generated.xml.firemon.Column;
import com.sp.generated.xml.firemon.Log;
import com.sp.generated.xml.firemon.LogTypes;
import com.sp.generated.xml.firemon.Member;
import com.sp.generated.xml.firemon.MemberCollection;
import com.sp.generated.xml.firemon.NetworkObject;
import com.sp.generated.xml.firemon.SecurityRule;
import com.sp.generated.xml.firemon.ServiceObject;
import com.sp.generated.xml.firemon.Zone;

/**
 * ExpressionBuilder for SecurityRules. For explanation see:
 * 
 * http://martinfowler.com/bliki/ExpressionBuilder.html
 * 
 * @author mtaylor
 */
public class SecurityRuleBuilder {
    private SecurityRule rule;
    private List<Zone> srcZones;
    private List<Zone> destZones;
    private List<ServiceObject> services;
    private List<NetworkObject> srcAddresses;
    private List<NetworkObject> destAddresses;
    private LogTypes ruleLogTypes;

    private SecurityRuleBuilder() {
        srcZones = new ArrayList<Zone>();
        destZones = new ArrayList<Zone>();
        services = new ArrayList<ServiceObject>();
        srcAddresses = new ArrayList<NetworkObject>();
        destAddresses = new ArrayList<NetworkObject>();

        rule = new SecurityRule();
        rule.setName(NormalizedData.createStringProperty(""));
        rule.setDisabled(NormalizedData.createBooleanProperty(false));
        rule.setLog(new Log());
        ruleLogTypes = LogTypes.NONE;
    }

    public static SecurityRuleBuilder beginRule(String number) {
        SecurityRuleBuilder builder = new SecurityRuleBuilder();
        builder.number(number);
        return builder;
    }

    public SecurityRule build() {
        rule.setService(createColumn(services));
        rule.setSourceZone(createColumn(srcZones));
        rule.setDestinationZone(createColumn(destZones));
        rule.setSource(createColumn(srcAddresses));
        rule.setDestination(createColumn(destAddresses));
        rule.getLog().setValue(ruleLogTypes);

        return rule;
    }

    public SecurityRuleBuilder number(String number) {
        rule.setNumber(NormalizedData.createIntegerProperty(number));
        return this;
    }

    public SecurityRuleBuilder action(ActionTypes actionTypes) {
        Action action = new Action();
        action.setValue(actionTypes);
        rule.setAction(action);
        return this;
    }

    public SecurityRuleBuilder name(String name) {
        rule.setName(NormalizedData.createStringProperty(name));
        return this;
    }

    public SecurityRuleBuilder disabled(Boolean disabled) {
        rule.setDisabled(NormalizedData.createBooleanProperty(disabled));
        return this;
    }

    public SecurityRuleBuilder logType(LogTypes logTypes) {
        ruleLogTypes = logTypes;
        return this;
    }

    public SecurityRuleBuilder comment(String comment) {
        rule.setComment(NormalizedData.createStringProperty(comment));
        return this;
    }

    public SecurityRuleBuilder addSrcZone(Zone zone) {
        srcZones.add(zone);
        return this;
    }

    public SecurityRuleBuilder addDestZone(Zone zone) {
        destZones.add(zone);
        return this;
    }

    public SecurityRuleBuilder addSrcAddress(NetworkObject networkObject) {
        srcAddresses.add(networkObject);
        return this;
    }

    public SecurityRuleBuilder addDestAddress(NetworkObject networkObject) {
        destAddresses.add(networkObject);
        return this;
    }

    public SecurityRuleBuilder addService(ServiceObject service) {
        services.add(service);
        return this;
    }

    @SuppressWarnings("rawtypes")
    private Column createColumn(Collection collection) {
        Column column = new Column();
        column.setMembers(new MemberCollection());
        column.setNegated(NormalizedData.createBooleanProperty(false));

        for (Object object : collection) {
            Member member = new Member();
            member.setObject(object);
            column.getMembers().getMembers().add(member);
        }

        return column;
    }

}
